#pragma once
#include "Buffer.h"
#include "Callbacks.h"
#include "InetAddress.h"
#include "Noncopyable.h"
#include "Timestamp.h"
#include <atomic>
#include <memory>
#include <string>

class Channel;
class EventLoop;
class Socket;

class TcpConnection : Noncopyable,
                      public std::enable_shared_from_this<TcpConnection>
{
  public:
    enum STATUS
    {
        CONNECTING,
        CONNECTED,
        DISCONNECTED,
        DISCONNECTING
    };

  private:
    EventLoop *loop_; // 不是mainLoop，mainLoop中封装好TcpConnection给subLoop
    const std::string name_;
    std::atomic<STATUS> state_;
    bool reading_;

    std::unique_ptr<Socket> socket_;
    std::unique_ptr<Channel> channel_;
    const InetAddress localAddr_;
    const InetAddress peerAddr_;

    ConnectionCallback connectionCallback_;
    MessageCallback messageCallback_;
    WriteCompleteCallback writeCompleteCallback_;
    CloseCallback closeCallback_;
    HighWaterMarkCallback highWaterMarkCallback_;

    size_t highWaterMark_;
    Buffer inputBuffer_;
    Buffer outputBuffer_;

  public:
    TcpConnection(EventLoop *loop, const std::string &name, int sockfd,
                  const InetAddress &localAddr, const InetAddress &peerAddr);
    ~TcpConnection();

    EventLoop *getLoop() const
    {
        return loop_;
    }
    const std::string &name() const
    {
        return name_;
    }
    const InetAddress &localAddress() const
    {
        return localAddr_;
    }
    const InetAddress &peerAddress()
    {
        return peerAddr_;
    }

    bool connected() const
    {
        return state_ == CONNECTED;
    }

    void send(const std::string &msg);
    void shutdown();

    void setState(STATUS state)
    {
        state_ = state;
    }
    void setConnectionCallback(const ConnectionCallback &cb)
    {
        connectionCallback_ = std::move(cb);
    }
    void setMessageCallback(const MessageCallback &cb)
    {
        messageCallback_ = std::move(cb);
    }
    void setWriteCompleteCallback(const WriteCompleteCallback &cb)
    {
        writeCompleteCallback_ = std::move(cb);
    }
    void setCloseCallback(const CloseCallback &cb)
    {
        closeCallback_ = std::move(cb);
    }
    void setHighWaterMarkCallback(const HighWaterMarkCallback &cb)
    {
        highWaterMarkCallback_ = std::move(cb);
    }

    void connectEstablished();
    void connectDestroyed();

  private:
    void handleRead(Timestamp receiveTIme);
    void handleWrite();
    void handleClose();
    void handleError();

    void sendInLoop(const void *message, size_t len);
    void shutdownInLoop();

}; // class TcpConnection
